﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;

namespace CloudShot.Utils.Drawings
{
	public static class GraphicsExtensions
	{
		/// <summary>
		/// 
		/// </summary>
		/// <param name="graphics"></param>
		/// <param name="text"></param>
		/// <param name="cursorPosition">A cursorPosition of left top or right top corner (depends on <paramref name="onRightSide"/>) of the label in client coordinates.</param>
		/// <param name="ownerFont"></param>
		/// <param name="ownerWidth"></param>
		/// <param name="ownerHeight"></param>
		/// <param name="onRightSide"></param>
		public static void DrawTextUnderCursor(this Graphics graphics, string text, Point cursorPosition, Font ownerFont, int ownerWidth, int ownerHeight, bool onRightSide)
		{
			SizeF labelSize = TextRenderer.MeasureText(text, ownerFont);

			int x;

			if (onRightSide)
				x = (cursorPosition.X + labelSize.Width < ownerWidth) ? cursorPosition.X : cursorPosition.X - (int)labelSize.Width;
			else
				x = Math.Max(cursorPosition.X - (int)labelSize.Width, 0);

			int y = (cursorPosition.Y + labelSize.Height < ownerHeight) ? cursorPosition.Y : cursorPosition.Y - (int)labelSize.Height;

			if ((cursorPosition.Y > y) && (cursorPosition.X + labelSize.Width < ownerWidth))
				x = cursorPosition.X;

			var labelRect = new Rectangle(x, y, (int)labelSize.Width, (int)labelSize.Height);
			graphics.FillRectangle(Brushes.WhiteSmoke, labelRect);

			TextRenderer.DrawText(graphics, text, ownerFont, labelRect, Color.Black, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.LeftAndRightPadding);
		}

		public static void DrawLabelOverImage(this Image image, string text, Font font)
		{
			if (string.IsNullOrEmpty(text))
				return;

			using (var graphics = Graphics.FromImage(image))
			{
				graphics.DrawPictureLabel(new Rectangle(0, 0, image.Width, image.Height), text, font);
			}
		}

		public static void DrawPictureLabel(this Graphics graphics, Rectangle rect, string text, Font font)
		{
			graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;

			//calculating
			Size size = TextRenderer.MeasureText(text, font, rect.Size, TextFormatFlags.WordBreak);
			Rectangle textRect = new Rectangle(rect.X, rect.Bottom - size.Height, rect.Width, size.Height);

			//drawing
			graphics.FillRectangle(new SolidBrush(Color.FromArgb(200, Color.Black)), textRect);
			TextRenderer.DrawText(graphics, text, font, textRect, Color.WhiteSmoke, TextFormatFlags.WordBreak | TextFormatFlags.HorizontalCenter);
		}

		public static void DrawHint(this Graphics graphics, string text, Rectangle currentScreenClientBounds, Rectangle selectionRect, Font font)
		{
			graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;

			//calculating
			//Size size = TextRenderer.MeasureText(text, font, new Size(500, currentScreenClientBounds.Height), TextFormatFlags.WordBreak);
			Size size = TextRenderer.MeasureText(text, font);

			int x = (currentScreenClientBounds.Width - size.Width) / 2;
			int y = currentScreenClientBounds.Height - 100;
			var textRect = new Rectangle(x, y, size.Width, size.Height);
			textRect.Inflate(4, 4);

			if (selectionRect.IntersectsWith(textRect))
				return;

			graphics.FillRoundedRectangle(new SolidBrush(Color.FromArgb(150, Color.Black)), textRect, 2);
			graphics.DrawRoundedRectangle(Pens.Black, textRect, 2);

			TextRenderer.DrawText(graphics, text, font, textRect, Color.White, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
		}

		/// <summary>
		/// Draws cross with center in <paramref name="position"/>.
		/// </summary>
		/// <param name="graphics"></param>
		/// <param name="position">A position of the cross center in client coordinates.</param>
		/// <param name="ownerWidth"></param>
		/// <param name="ownerHeight"></param>
		public static void DrawCross(this Graphics graphics, Point position, int ownerWidth, int ownerHeight)
		{
			using (var pen = new Pen(Color.FromArgb(180, Color.Gray)))
			{
				graphics.DrawLine(pen, position.X, 0, position.X, ownerHeight);
				graphics.DrawLine(pen, 0, position.Y, ownerWidth, position.Y);
			}
		}

		public static void DrawOutlineText(this Graphics graphics, string text, Font font, int width, int height, Color textColor, Color outlineColor, int outlineWidth)
		{
			// Gradient brush example
			// this makes the gradient repeat for each text line
			// var fr = new Rectangle(0, lblCapturer.Height - font.Height, lblCapturer.Width, font.Height);
			// var brush = new LinearGradientBrush(fr, ColorTranslator.FromHtml("#FF6493"), ColorTranslator.FromHtml("#D00F14"), 90);

			using (var brush = new SolidBrush(textColor))
			{
				graphics.DrawOutlineText(text, font, width, height, brush, outlineColor, outlineWidth);
			}
		}

		public static void DrawOutlineText(this Graphics graphics, string text, Font font, int width, int height, Brush textBrush, Color outlineColor, int outlineWidth)
		{
			//float fontSize = 52;

			//this will center align our text at the bottom of the image
			var sf = new StringFormat
			{
				Alignment = StringAlignment.Center,
				LineAlignment = StringAlignment.Center
			};

			var p = new Pen(outlineColor, outlineWidth);
			p.LineJoin = LineJoin.Round; //prevent "spikes" at the path

			//this will be the rectangle used to draw and auto-wrap the text.
			//basically = image size
			var r = new Rectangle(0, 0, width, height);
			var gp = new GraphicsPath();

			//look mom! no pre-wrapping!
			gp.AddString(text, font.FontFamily, (int)font.Style, font.Size, r, sf);

			//these affect lines such as those in paths. Textrenderhint doesn't affect
			//text in a path as it is converted to ..well, a path.    
			graphics.SmoothingMode = SmoothingMode.AntiAlias;
			graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

			//TODO: shadow -> graphics.translate, fillpath once, remove translate
			graphics.DrawPath(p, gp);
			graphics.FillPath(textBrush, gp);

			//cleanup
			gp.Dispose();
			p.Dispose();
			sf.Dispose();
		}
	}
}